# proevolytx@gmail.com
# 2012/11/21

from translator_hi import *
from Tkinter import *
from StringIO import *
import sys

class App:
    def __init__(s):
        s.reportStr = None
        s.tokenStr = None
        s.parserStr = None
        s.highStr = None
        s.outputStr = None
        s.hi = None
        
        root = Tk()
        root.title("Minipy")
        s.root = root

        leftFrame = Frame(root)
        Label(leftFrame, text = "Minipy Code").pack(side = TOP, anchor = "w")
        codeText = Text(leftFrame, width = 60, height = 30)
        codeTextScroll = Scrollbar(leftFrame, command = codeText.yview)
        codeText.configure(yscrollcommand = codeTextScroll.set)
        codeText.pack(side = LEFT)
        codeTextScroll.pack(side = LEFT, fill = Y)
        leftFrame.pack(side = LEFT, pady = 10)
        s.codeText = codeText

        rightFrame = Frame(root)

        infoFrame = Frame(rightFrame)
        infoText = Text(infoFrame, width = 45, height = 25)
        infoText.pack(side = LEFT)
        infoScrollY = Scrollbar(infoFrame, command = infoText.yview)
        infoText.configure(yscrollcommand = infoScrollY.set)
        infoScrollY.pack(side = LEFT, fill = Y)
        infoFrame.pack(side = BOTTOM)
        s.infoText = infoText

        Label(rightFrame, text = "Infomation").pack(side = TOP, anchor = "w")

        frame1 = Frame(rightFrame)
        btnAnalyze = Button(
            frame1, text = "Analyze", command = s.AnalyzeClick)
        btnAnalyze.pack(side = LEFT, padx = 5)
        btnRun = Button(
            frame1, text = "Run", command = s.RunClick)
        btnRun.pack(side = LEFT, padx = 5)
        frame1.pack(side = TOP, anchor = "w", padx = 5)

        frame2 = Frame(rightFrame)
        btnReport = Button(
            frame2, text = "Report", command = s.ReportClick)
        btnReport.pack(side = LEFT, padx = 5)
        btnTokenFlow = Button(
            frame2, text = "Token Flow", command = s.TokenFlowClick)
        btnTokenFlow.pack(side = LEFT, padx = 5)
        btnParserTree = Button(
            frame2, text = "Parser Tree", command = s.ParserTreeClick)
        btnParserTree.pack(side = LEFT, padx = 5)
        btnHighLevel = Button(
            frame2, text = "Intermediate", command = s.HighLevelClick)
        btnHighLevel.pack(side = LEFT, padx = 5)
        btnOutput = Button(
            frame2, text = "Output", command = s.OutputClick)
        btnOutput.pack(side = LEFT, padx = 5)
        frame2.pack(side = TOP, anchor = "w", padx = 5, pady = 5)

        rightFrame.pack(side = LEFT, padx = 10)

        root.mainloop()

    def ReportClick(s):
        s.infoText.delete("1.0", END)
        if s.reportStr is None:
            s.infoText.insert("1.0", "Please analyze first!")
        else:
            s.infoText.insert("1.0", s.reportStr)
                          
    def TokenFlowClick(s):
        s.infoText.delete("1.0", END)
        if s.tokenStr is None:
            s.infoText.insert("1.0", "Please analyze first!")
        else:
            s.infoText.insert("1.0", s.tokenStr)

    def ParserTreeClick(s):
        s.infoText.delete("1.0", END)
        if s.parserStr is None:
            s.infoText.insert("1.0", "Please analyze first!")
        else:
            s.infoText.insert("1.0", s.parserStr)

    def HighLevelClick(s):
        s.infoText.delete("1.0", END)
        if s.highStr is None:
            s.infoText.insert("1.0", "Please analyze first!")
        else:
            s.infoText.insert("1.0", s.highStr)

    def OutputClick(s):
        s.infoText.delete("1.0", END)
        if s.outputStr is None:
            s.infoText.insert("1.0", "Please run first!")
        else:
            s.infoText.insert("1.0", s.outputStr)

    def PrintLog(s, text, newLine = True):
        s.infoText.insert(END, text)
        if newLine:
            s.infoText.insert(END, "\n")

    def AnalyzeClick(s):
        s.reportStr = None
        s.tokenStr = None
        s.parserStr = None
        s.highStr = None
        s.outputStr = None
        s.hi = None
        error = False
        
        s.infoText.delete("1.0", END)
        s.infoText.insert(
            END, strftime('Time %H:%M:%S\n', localtime(time())))
        s.infoText.insert(END, "Analyzing...\n")
        
        code = s.codeText.get("1.0", END)
        fs = StringStream(code)

        roughReport = ""

        stdoutBackup = sys.stdout
        sys.stdout = StringIO()
        
        try:
            start = clock()
            lex = Lexer()
            lexerBuildTime = clock() - start

            parser = BuildParser(4)
            parseResults = Parse(fs, lex, parser, "")

            start = clock()
            hi = []
            settings = {"label" : 0, "var" : 0, "loop" : [], "ex" : 0}
            tree = parseResults["__main__"]["parser-out"]
            Translate(tree, hi, [set()], settings)
            hi.append(["halt"])
            translateTime = clock() - start

            tokenCount = 0
            nodeCount = 0
            lineCount = 0
            totalLexerTime = 0
            totalParserTime = 0
            for r in parseResults:
                tokenCount += parseResults[r]["lexer-tokens"]
                nodeCount += parseResults[r]["parser-nodes"]
                lineCount += parseResults[r]["lexer-lines"]
                totalLexerTime += parseResults[r]["lexer-time"]
                totalParserTime += parseResults[r]["parser-time"]

            print "Total Statistics"
            print "File count : ", len(parseResults)
            print "Total lines of code : ", lineCount
            print "Total token count : ", tokenCount
            print "Total syntax tree size : ", nodeCount
            print "Total instruction count : ", len(hi)
            print

            print "Time Statistics"
            print "Lexer build time :", str(lexerBuildTime)[:5], "seconds"
            print "Total lexer time: ", str(totalLexerTime)[:5], "seconds"
            print "Total parser time: ",  str(totalParserTime)[:5], "seconds"
            print "Total translator time: ", str(translateTime)[:5], "seconds"
            print 

            for r in parseResults:
                print "Module:", r
                print "Lines of code:", parseResults[r]["lexer-lines"]
                print "Lexer time:", \
                      str(parseResults[r]["lexer-time"])[:5], "seconds"
                print "Lexer token count:", parseResults[r]["lexer-tokens"]
                print "Parser time:", \
                      str(parseResults[r]["parser-time"])[:5], "seconds"
                print "Parser tree size:", parseResults[r]["parser-nodes"]
                print
                
            roughReport = "Analyze successfully."
            
        except Exception, e:
            roughReport = "Error : " + str(e)
            error = True

        s.infoText.insert(END, roughReport)
        s.reportStr = sys.stdout.getvalue()

        if error:
            s.reportStr = None
            sys.stdout = stdoutBackup
            return

        s.hi = hi

        sys.stdout = StringIO()
        for r in parseResults:
            print "Module :", r
            tokens = parseResults[r]["lexer-out"]
            print "Token count :", len(tokens)
            for t in tokens:
                print t["line"],
                for key in t:
                    if key not in ["line", "type"]:
                        print t[key],
                print t["type"]
            print
        s.tokenStr = sys.stdout.getvalue()

        sys.stdout = StringIO()
        print "Altogether tree size :", nodeCount
        print "Syntax Tree :"
        tree = parseResults["__main__"]["parser-out"]
        count = SimplePrint(tree)
        s.parserStr = sys.stdout.getvalue()

        sys.stdout = StringIO()
        print "Altogether instruction count :", len(hi)
        print "Instructions :"
        for h in hi:
            for i in h:
                print i, "\t",
            print
        s.highStr = sys.stdout.getvalue()
        
        s.outputStr = None

        sys.stdout = stdoutBackup

    def RunClick(s):
        if s.hi is None:
            s.infoText.delete("1.0", END)
            s.infoText.insert("1.0", "Please analyze first!")
            return

        stdoutBackup = sys.stdout
        sys.stdout = StringIO()
        try:
            print "============================================"
            print "Loading Instruction..."
            mac = MachineHi()
            mac.Load(s.hi)
            print "Simulating..."
            print "============================================"
            start = clock()
            mac.Simulate(0)
            print "============================================"
            print "Simulation finished"
            print "Instruction executed :", mac.instcount
            print "Time consumed :", str(clock() - start)[:5], "seconds"
            print "============================================"
        except Exception, e:
            print "Error :"
            print e
            print "============================================"
        s.outputStr = sys.stdout.getvalue()
        sys.stdout = stdoutBackup
        
        s.infoText.delete("1.0", END)
        s.infoText.insert("1.0", s.outputStr)

if __name__ == "__main__":
    App()
